<template>
  <view class="speaking-wrapper">
    <view class="speaking-operate" v-if="!isSpeaking">
      <image class="operate-side" :src="props.prevIcon" @click="handleToPrev" />
      <image class="operate-center" :src="curVoiceImage" @click="handleListenUserVoice" />
      <image class="operate-center" src="https://rwstatic.tentons.cn/web/Lesson/images/speaking-voice.png"
        @click="handleSpeak">
        <slot name="operate-content"></slot>
      </image>
      <image class="operate-side" :src="props.nextIcon" @click="handleToNext" />
    </view>
    <view class="speaking-scene" v-if="isSpeaking">
      <view class="scene-wrapper">
        <view class="scene-btn">
          <image class="icon" src="https://rwstatic.tentons.cn/web/Lesson/images/time-icon.png" />
          <text class="label">{{ speakTime }}s</text>
        </view>
        <text class="scene-label">点击波纹，结束录音</text>
        <view class="scene-btn" @click="handleReSpeaking">
          <image class="icon" src="https://rwstatic.tentons.cn/web/Lesson/images/replay-icon.png" />
          <text class="label">重录</text>
        </view>
      </view>
      <image class="scene-wavy" src="https://rwstatic.tentons.cn/web/Lesson/images/speaking-wavy.png"
        @click="handleStopSpeaking" />
    </view>
  </view>
</template>

<script setup lang="ts">
import { computed, onBeforeUnmount, ref } from "vue";
import { Recorder } from "@/utils/recorder";
// @ts-ignore
import { ossUpload } from "@/utils/oss/oss.js";
import { AudioManager } from "@/utils/AudioManager";
import env from "@/config/env";
import type { IUploadSuccessInfo } from "./recordSound.vue";
import { util } from "@/utils/util";

const speakingStart = "https://rwstatic.tentons.cn/web/Lesson/images/speaking-start.png";
const speakingStartActive = "https://rwstatic.tentons.cn/web/Lesson/images/speaking-start-active.png";
const speakingStop = "https://rwstatic.tentons.cn/web/Lesson/images/speaking-stop.png";

interface IProps {
  voice: string;
  prevIcon?: string;
  nextIcon?: string;
}

const props = withDefaults(defineProps<IProps>(), {
  prevIcon: "https://rwstatic.tentons.cn/web/Lesson/images/speaking-prev.png",
  nextIcon: "https://rwstatic.tentons.cn/web/Lesson/images/speaking-next.png",
})

var recorder: Recorder;

let timer: number | undefined;
const speakTime = ref(0);
const isListen = ref(false);
const isSpeaking = ref(false);
const fullAudioSrc = ref("");
const isWaitStart = ref(false);

const curVoiceImage = computed(() => {
  return props.voice ? (isListen.value ? speakingStop : speakingStartActive) : speakingStart;
});

const emits = defineEmits<{
  (e: "prev"): void;
  (e: "next"): void;
  (e: "onStartUpload"): void;
  (e: "onUploadSuccess", info: IUploadSuccessInfo): void;
}>();

const getRecorder = () => {
  if (!recorder) {
    recorder = new Recorder();
  }
  return recorder;
};

const handleListenUserVoice = () => {
  if (!props.voice) {
    return;
  }

  if (isListen.value) {
    AudioManager.getInstance().pause({
      src: `${env.prefixUrl}${props.voice}`,
      onVoicePause: () => {
        isListen.value = false;
        uni.$emit("is-audio-play", { isAudioStop: false });
      }
    });
  } else {
    AudioManager.getInstance().play({
      src: `${env.prefixUrl}${props.voice}`,
      onVoiceStart: () => {
        isListen.value = true;
        uni.$emit("is-audio-play", { isAudioStop: true });
      },
      onVoiceStop: () => {
        isListen.value = false;
        uni.$emit("is-audio-play", { isAudioStop: false });
      },
      onVoiceEnded: () => {
        isListen.value = false;
        uni.$emit("is-audio-play", { isAudioStop: false });
      }
    });
  }
};

const handleToPrev = () => {
  emits("prev");
};

const handleToNext = () => {
  emits("next");
};

const handleStartRecorder = () => {
  getRecorder().start({
    onStart: () => {
      isWaitStart.value = false;
      isSpeaking.value = true;
      timer = setInterval(() => {
        speakTime.value += 1;
      }, 1000);
    },
    onSuccess: (res) => {
      fullAudioSrc.value = res.fullFilePath;
      emits("onStartUpload");

      ossUpload(res.fullFilePath).then((val: any) => {
        emits("onUploadSuccess", { localFilePath: res.fullFilePath, ossFilePath: `front-course/h5/${val.data.fileName}` });
      });
    },
    onFail: (errorMsg) => {
      isWaitStart.value = false;
      util.showDialogue("录音失败:" + errorMsg);
    },
    onComplete: () => {
      clearInterval(timer);
      speakTime.value = 0;
      isSpeaking.value = false;
    },
  });
};

const handleSpeak = () => {
  if (isWaitStart.value) {
    return;
  }
  isWaitStart.value = true;
  handleStartRecorder();
};

const handleReSpeaking = () => {
  getRecorder().cancel(() => {
    clearInterval(timer);
    speakTime.value = 0;
    fullAudioSrc.value = "";
    setTimeout(() => {
      handleStartRecorder();
    }, 500);
  });
};

const handleStopSpeaking = () => {
  getRecorder().stop();
};

onBeforeUnmount(() => {
  getRecorder().cancel(() => { });
  AudioManager.getInstance().stop();
  clearInterval(timer);
  speakTime.value = 0;
});
</script>

<style scoped lang="scss">
.speaking-wrapper {
  position: relative;
  width: 100%;

  .speaking-operate {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 6rem;
    padding: 0 3rem;

    .operate-side {
      width: 3rem;
      height: 3rem;
    }

    .operate-center {
      width: 6rem;
      height: 6rem;
    }
  }

  .speaking-scene {
    position: relative;
    width: 100%;
    height: 9.8rem;
    animation: fadeIn 0.3s linear 0s;
    animation-fill-mode: both;
    opacity: 0;

    @keyframes fadeIn {
      0% {
        opacity: 0;
        transform: translateY(9.8rem);
      }

      100% {
        opacity: 1;
        transform: translateY(0);
      }
    }

    .scene-wrapper {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 0 3rem;
      margin-bottom: 3rem;

      .scene-btn {
        display: flex;
        align-items: center;

        .icon {
          width: 1.8rem;
          height: 1.8rem;
          margin-right: 0.2rem;
        }

        .label {
          font-size: 1.4rem;
          font-family: xiaolai;
          color: $uni-text-color-btn;
        }
      }

      .scene-label {
        font-size: 1.4rem;
        font-family: xiaolai;
        color: $uni-text-color-grey;
      }
    }

    .scene-wavy {
      width: 100%;
      height: 3rem;
    }
  }

  .speaking-scene-leave {
    opacity: 1;
    animation: fadeOut 0.3s linear 0s;
    animation-fill-mode: both;

    @keyframes fadeOut {
      0% {
        display: inline-block;
        opacity: 1;
        transform: translateY(0);
      }

      100% {
        display: inline-block;
        opacity: 0;
        transform: translateY(-9.8rem);
      }
    }
  }
}
</style>
